Author: Jessica Marx
Date: 01 August 2019
# load packages, install if needed
packages = c(
"dplyr"
, "ggplot2"
, "formattable"
, "plotly"
, "RColorBrewer"
, "scales"
, "stringr"
, "tidyr"
, "ElmeR"
, "RJDBC"
, "kableExtra"
, "wesanderson"
, "reshape2"
, "rtweet"
, "tidytext"
, "lubridate"
, "wordcloud"
, "ggpubr"
, "ggthemes"
, "knitrBootstrap"
, "DT"
, "MatchIt"
, "beyonce"
, "UpSetR"
, "gganimate"
, "wordcloud2"
, "widyr"
, "ggraph"
, "igraph"
, "aod"
, "corrplot"
, "ROCR"
, "InformationValue"
, "car"
, "glmnet"
, "caret"
, "kernlab"
, "pdp"
, "rpart.plot"
, "rpart"
, "e1071"
)
package.check <- lapply(packages, FUN = function(x) {
if (!require(x, character.only = TRUE)) {
install.packages(x, dependencies = TRUE)
library(x, character.only = TRUE)
}
})
options(scipen= 999)
theme_set(theme_minimal(base_size = 9, base_family = "Roboto"))
#functions!
#round
round.to <- function(x, b) {
round(x/b)*b
}
#odds to probability
odds.to.prob <- function(odds) {
odds/(1 + odds)
}
#log odds to probability
logit2prob <- function(logit){
odds <- exp(logit)
prob <- odds / (1 + odds)
return(prob)
}
#convert to a range
range01 <- function(x){
(x-min(x))/(max(x)-min(x))
}
#function to get vector of color values from RColorBrewer
get_hex_values <- function(pal) {
brewer.pal(brewer.pal.info[pal, "maxcolors"], pal)
}
paired_cols <- get_hex_values(pal = "Paired")
Top Dog Breeds
a = seattle_pet_licenses %>%
filter(species == "Dog") %>%
select(primary_breed, license_issue_date) %>%
mutate(license_issue_date = as.Date(license_issue_date),
year = lubridate::year(license_issue_date)) %>%
group_by(primary_breed, year) %>%
count() %>%
arrange(year, desc(n)) %>%
ungroup() %>%
group_by(year) %>%
mutate(rank = row_number()) %>%
filter(rank <= 5, year >= 2010) %>%
mutate(rev_rank = rank(-rank)) %>%
ungroup()
colourCount = length(unique(a$primary_breed))
getPalette = colorRampPalette(brewer.pal(12, "Paired"))
ggplot(a, aes(x = year, y = reorder(rev_rank, rev_rank), fill = primary_breed)) +
geom_bar(stat = "identity", position = "stack", color = "white") +
geom_text(stat = "identity", position = "stack", aes(label = rank), color = "black", size = 3, vjust = 1, hjust = 3) +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
scale_x_continuous(breaks = seq(2010, 2016, 1)) +
coord_flip() +
ylab("rank") +
scale_fill_manual(values = getPalette(colourCount), name = "Breed") +
ggtitle(label = "Top Five Seattle Dog Breeds by Year")

Breed Acceleration
a = seattle_pet_licenses %>%
filter(species == "Dog") %>%
select(primary_breed, license_issue_date) %>%
mutate(license_issue_date = as.Date(license_issue_date),
year = lubridate::year(license_issue_date)) %>%
filter(year >= 2015) %>%
group_by(primary_breed, year) %>%
count() %>%
spread(year, n) %>%
drop_na() %>%
mutate(pct_increase = `2016`/`2015`-1) %>%
arrange(desc(pct_increase)) %>%
head(20) %>%
ungroup()
b = seattle_pet_licenses %>%
filter(species == "Dog") %>%
select(secondary_breed, license_issue_date) %>%
mutate(license_issue_date = as.Date(license_issue_date),
year = lubridate::year(license_issue_date)) %>%
filter(year >= 2015) %>%
group_by(secondary_breed, year) %>%
count() %>%
spread(year, n) %>%
drop_na() %>%
mutate(pct_increase = `2016`/`2015`-1) %>%
arrange(desc(pct_increase)) %>%
head(20) %>%
ungroup()
breeds = a %>%
select(primary_breed, pct_increase) %>%
rename("breed" = primary_breed) %>%
mutate(breed_level = "Primary Breed") %>%
rbind(
b %>%
select(secondary_breed, pct_increase) %>%
rename("breed" = secondary_breed) %>%
mutate(breed_level = "Secondary Breed")
) %>%
group_by(breed_level) %>%
arrange(breed_level, desc(pct_increase)) %>%
mutate(rank = row_number()) %>%
ungroup()
colourCount = length(unique(breeds$breed))
getPalette = colorRampPalette(brewer.pal(12, "Paired"))
breeds %>%
ggplot(aes(x = reorder(breed, -rank), y = pct_increase, fill = breed)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = getPalette(colourCount), name = "Breed") +
scale_y_continuous(labels = percent_format()) +
ylab("Percent Increase") +
xlab("Breed") +
ggtitle(label = "Year Over Year (YOY) Increase in Breeds") +
coord_flip() +
theme(legend.position = "none") +
facet_wrap(~breed_level, scales = "free_y")

Dog Names
a = seattle_pet_licenses %>%
filter(species == "Dog",
!is.na(animal_s_name)) %>%
select(animal_s_name, license_issue_date) %>%
mutate(animal_s_name = if_else(is.na(animal_s_name), "No Name", animal_s_name) ,
license_issue_date = as.Date(license_issue_date),
year = lubridate::year(license_issue_date)) %>%
group_by(animal_s_name, year) %>%
count() %>%
arrange(year, desc(n)) %>%
ungroup() %>%
group_by(year) %>%
mutate(rank = row_number()) %>%
filter(rank <= 5, year >= 2010) %>%
mutate(rev_rank = rank(-rank)) %>%
ungroup()
colourCount = length(unique(a$animal_s_name))
getPalette = colorRampPalette(brewer.pal(12, "Paired"))
ggplot(a, aes(x = year, y = reorder(rev_rank, rev_rank), fill = animal_s_name)) +
geom_bar(stat = "identity", position = "stack", color = "white") +
scale_fill_manual(values = getPalette(colourCount), name = "Name") +
geom_text(stat = "identity", position = "stack", aes(label = rank), color = "black", size = 3, vjust = 1, hjust = 3) +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
scale_x_continuous(breaks = seq(2010, 2016, 1)) +
coord_flip() +
ylab("rank") +
ggtitle(label = "Top Five Seattle Dog Names by Year")

Breed Combos
Breed Heatmap
Which primary and secondary breek combinations are most popular?
top_breeds = rbind(
(seattle_pet_licenses %>%
filter(species == "Dog") %>%
select(primary_breed) %>%
group_by_all() %>%
count() %>%
arrange(desc(n)) %>%
head(20) %>%
rename("breed" = primary_breed)),
(seattle_pet_licenses %>%
filter(species == "Dog") %>%
select(secondary_breed) %>%
group_by_all() %>%
count() %>%
arrange(desc(n)) %>%
head(20) %>%
rename("breed" = secondary_breed)
)) %>%
group_by(breed) %>%
summarise(n = sum(n)) %>%
arrange(desc(n)) %>%
ungroup() %>%
mutate(breed = if_else(is.na(breed), "Unknown", breed))
plot = seattle_pet_licenses %>%
filter(species == "Dog",
primary_breed %in% top_breeds$breed
,secondary_breed %in% top_breeds$breed
) %>%
select(primary_breed, secondary_breed) %>%
mutate(secondary_breed = if_else(is.na(secondary_breed), primary_breed, secondary_breed)) %>%
group_by_all() %>%
count() %>%
arrange(desc(n)) %>%
#head(50) %>%
mutate(log = log(n + 1)) %>%
ggplot(
aes(x = primary_breed,
y = secondary_breed,
fill = log,
text = paste(
"Primary Breed:", primary_breed,
"<br>Secondary Breed:", secondary_breed,
"<br>Dogs:", comma(n)
)
)
) +
geom_tile() +
theme(axis.text.x = element_text(angle = -30, hjust = 0)) +
scale_fill_gradientn(colours = blues9,
na.value = "white",
breaks=c(0,7),
# # # #breaks = c(400, 700000),
labels=c("0","1K"),
limits=c(0,7),
# # # #limits = c(400, 700000),
name = "Dogs") +
ylab("Secondary Breed") +
xlab("Primary Breed")
ggplotly(plot, tooltip = "text") %>%
layout(autosize = F, width = 800, height = 600)
Upset Plot (like a Venn Diagram, but better)
#This is the true code for this plot. Unfortunately, this package has a bug -- one that prints a giant blank space before the plot, which makes it less than optimal for publishing. My hack around this is to reproduce the plot using this code and save the image in my R Project file. From there I can just pull it in with html. A hack, yes, but one that works until the bug is fixed (according to their GitHub page, it's a WIP!).
# upset_dog = rbind(
# (seattle_pet_licenses %>%
# filter(species == "Dog") %>%
# mutate(primary_breed = if_else(is.na(primary_breed), "Unknown", primary_breed)) %>%
# select(primary_breed, license_number) %>%
# rename("breed" = primary_breed)),
# (seattle_pet_licenses %>%
# filter(species == "Dog") %>%
# mutate(secondary_breed = if_else(is.na(secondary_breed), "Unknown", secondary_breed)) %>%
# select(secondary_breed, license_number) %>%
# rename("breed" = secondary_breed)
# )) %>%
# group_by(license_number, breed) %>%
# count() %>%
# mutate(value = 1) %>%
# select(-license_number, -n) %>%
# spread(breed, value, fill = 0) %>%
# as.data.frame()
#
# upset(upset_dog,
# order.by = "freq",
# nsets = 15,
# mainbar.y.label = "Dog Breed Intersections",
# sets.x.label = "Total Number of Breed in Sample",
# matrix.color = "#3288bd",
# main.bar.color = "#f46d43",
# sets.bar.color = "#3288bd",
# point.size = 2.5, line.size = 1,
# nintersects = 15,
# shade.color = "#9e0142",
# text.scale = c(1.5, 1.5, 1.5, 1.5, 1.5, 1.5),
# group.by = "degree")
Breed Characteristics
What are the words used to describe different dog breeds? All breed descriptions were obtained through the Pet Breeds Characteristics public dataset.

We will score the top 20 breeds using the AFINN lexicon, which scores words by sentiment.
Before doing so, let’s inspect the data and make sure that we agree with the way the Lexicon is classifying words given our specific context.
AFINN <- get_sentiments("afinn")
pal <- rev(beyonce_palette(22, 100, type = "continuous"))
plot_c = barsentiment %>%
dplyr::count(sentiment, word, n=n) %>%
dplyr::ungroup()
dog_breed_characteristics %>%
select(BreedName, Group1, Group2, Temperment) %>%
unnest_tokens(word, Temperment) %>%
inner_join(AFINN) %>%
select(word, score) %>%
unique() %>%
arrange(desc(score)) %>%
mutate(Sentiment = if_else(score > 0, "Positive", "Negative")) %>%
ggplot(aes(x = reorder(word, score), y = score, fill = Sentiment)) +
geom_bar(stat = "identity") +
scale_fill_brewer(palette = "Set1") +
coord_flip() +
xlab("Word") +
ylab("Score")

A dog being alert does not seem like it would be a bad thing - let’s change that from a -1 to a +1.
Some dog breeds are described by more words than others. A histogram helps us visualize and normalize the data.

Now we’re ready to score our dogs by breed.
Top 20
dog_scores %>%
arrange(desc(total_score)) %>%
head(20) %>%
ggplot(aes(x = reorder(BreedName, total_score), y = total_score, fill = total_score)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(
colours = pal, name = "Score") +
coord_flip() +
xlab("Breed") +
ylab("Total Word Score")

Are dogs with more words scored higher? We can normalize by taking the mean word score.
dog_scores %>%
arrange(desc(mean_score), BreedName) %>%
head(20) %>%
ggplot(aes(x = reorder(BreedName, mean_score), y = mean_score, fill = total_score)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(
colours = pal, name = "Total Score") +
coord_flip() +
xlab("Breed") +
ylab("Mean Word Score")

Top 20 Breed Combos

By Group
Let’s hear it for the the Hounds!
group_scores = dog_words %>%
filter(!Group1 == "Southern") %>%
select(Group1, word) %>%
unique() %>%
inner_join(AFINN) %>%
group_by(Group1) %>%
summarise(avg_score = mean(score),
score = sum(score)) %>%
drop_na()
group_scores %>%
arrange(desc(avg_score)) %>%
#head(20) %>%
ggplot(aes(x = reorder(Group1, avg_score), y = avg_score, fill = score)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(
colours = pal, name = "Total Score") +
coord_flip() +
xlab("Breed Group") +
ylab("Mean Score")

Breed Group 1 + Group 2
group_both = dog_words %>%
filter(!Group1 == "Southern") %>%
inner_join(AFINN) %>%
mutate(group_combo = paste(Group1, Group2, sep = " + ")) %>%
group_by(group_combo) %>%
summarise(
avg_score = mean(score),
score = sum(score)
) %>%
#summarise(count = n_distinct(word)) %>%
drop_na()
group_both %>%
arrange(desc(avg_score)) %>%
#head(20) %>%
ggplot(aes(x = reorder(group_combo, avg_score), y = avg_score, fill = score)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(
colours = pal, name = "Total Score") +
coord_flip() +
xlab("Breed Group 1 + Breed Group 2") +
ylab("Mean Score")

Intelligence Ratings
Does intelligence correspond with price? No.
Pets by Zip YOY
seattle_pet_licenses %>%
drop_na() %>%
select(license_issue_date
, species
, zip_code
, license_number) %>%
mutate(license_issue_date = as.Date(license_issue_date),
year = lubridate::year(license_issue_date),
zip_code = (as.factor(zip_code))
) %>%
group_by(year, zip_code, species) %>%
summarise(new_pets = n_distinct(license_number)) %>%
ungroup() %>%
plot_ly(
x = ~zip_code
, y = ~new_pets
, color = ~species
, type = "bar"
, legend_group = ~species
, frame = ~year
) %>%
layout(
barmode = "stack"
, xaxis = list(title = "Zip Code")
, yaxis = list(title = "New Pets")
)
LS0tCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IGZhbHNlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgCi0tLQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKYm9keSB7CiAgZm9udC1zaXplOiAxMnB0OwogIGZvbnQtZmFtaWx5OiAiUm9ib3RvIiwgc2Fucy1zZXJpZjsKfQoKdGggewogICAgYmFja2dyb3VuZC1jb2xvcjogI2E2Y2VlMzsKICAgIGNvbG9yOiBibGFjazsKICAgIGZvbnQtc2l6ZTogMTBwdDsKICAgIGZvbnQtZmFtaWx5OiAiUm9ib3RvIiwgc2Fucy1zZXJpZjsKICAgIHRleHQtYWxpZ246IGxlZnQ7CiAgICA8IS0tIG1hcmdpbi1sZWZ0OiBhdXRvOyAtLT4KICAgIDwhLS0gbWFyZ2luLXJpZ2h0OiBhdXRvOyAtLT4KICAgIDwhLS0gcGFkZGluZy10b3A6IDI1cHg7IC0tPgogIH0KCnRkIHsgIC8qIFRhYmxlICAqLwogIGZvbnQtc2l6ZTogMTBwdDsKICA8IS0tIHRleHQtYWxpZ246IGNlbnRlcjsgLS0+CiAgZm9udC1mYW1pbHk6ICJSb2JvdG8iLCBzYW5zLXNlcmlmOwogIDwhLS0gcGFkZGluZy10b3A6IDI1cHg7IC0tPgp9CgpoMSB7CiAgZm9udC1zaXplOiAxNnB0OwogIGZvbnQtZmFtaWx5OiAiT3N3YWxkIiwgc2Fucy1zZXJpZjsKfQogIApoMiB7CiAgZm9udC1zaXplOiAxNHB0OwogIGZvbnQtZmFtaWx5OiAiT3N3YWxkIiwgc2Fucy1zZXJpZjsKICA8IS0tIGNvbG9yOiAjMWY3OGI0OyAtLT4KICBmb250LWZhbWlseTogIk9zd2FsZCIsIHNhbnMtc2VyaWY7Cn0KCmgzIHsKICBmb250LXNpemU6IDE0cHQ7CiAgZm9udC1mYW1pbHk6ICJPc3dhbGQiLCBzYW5zLXNlcmlmOwogIH0KICAKaDQgewogIGZvbnQtc2l6ZTogMTJwdDsKICBmb250LWZhbWlseTogIk9zd2FsZCIsIHNhbnMtc2VyaWY7Cn0KaDUgewogIGZvbnQtc2l6ZTogMTJwdDsKICBmb250LWZhbWlseTogIk9zd2FsZCIsIHNhbnMtc2VyaWY7Cn0KYSB7CiAgY29sb3I6ICMxZjc4YjQ7CiAgZm9udC1zaXplOiAxMnB0OwogIGZvbnQtZmFtaWx5OiAiT3N3YWxkIiwgc2Fucy1zZXJpZjsKfQoKCi5zaWRlbmF2IHsKICBoZWlnaHQ6IDEwMCU7CiAgd2lkdGg6IDIwMHB4OwogIHBvc2l0aW9uOiBmaXhlZDsKICB6LWluZGV4OiAxOwogIHRvcDogMDsKICBsZWZ0OiAwOwogIGJhY2tncm91bmQtY29sb3I6ICNhNmNlZTM7CiAgb3ZlcmZsb3cteDogaGlkZGVuOwogIHBhZGRpbmctdG9wOiAyMHB4Owp9Cgouc2lkZW5hdiBhIHsKICBwYWRkaW5nOiA2cHggOHB4IDZweCAxNnB4OwogIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICBmb250LXNpemU6IDE4cHQ7CiAgPCEtLSBmb250LXdlaWdodDogYm9sZGVyOyAtLT4KICBmb250LWZhbWlseTogIk9zd2FsZCIsIHNhbnMtc2VyaWY7CiAgY29sb3I6ICNGRkZGRkY7CiAgZGlzcGxheTogYmxvY2s7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgouY2VudGVyIHsKICBkaXNwbGF5OiBibG9jazsKICBtYXJnaW4tbGVmdDogYXV0bzsKICBtYXJnaW4tcmlnaHQ6IGF1dG87CiAgd2lkdGg6IDEwMCU7Cn0KCi5zaWRlbmF2IGE6aG92ZXIgewogIGNvbG9yOiAjZjFmMWYxOwp9CgoubWFpbiB7CiAgbWFyZ2luLWxlZnQ6IDIwMHB4OyAvKiBTYW1lIGFzIHRoZSB3aWR0aCBvZiB0aGUgc2lkZW5hdiAqLwoKfQoubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTQwMHB4OwogIG1hcmdpbi1sZWZ0OiBhdXRvOwogIG1hcmdpbi1yaWdodDogYXV0bzsKICBwYWRkaW5nOiAyNXB4Cn0KICAvKnBhZGRpbmc6IDBweCA1cHg7ICovCn0KCkBtZWRpYSBzY3JlZW4gYW5kIChtYXgtaGVpZ2h0OiA0NTBweCkgewogIC5zaWRlbmF2IHtwYWRkaW5nLXRvcDogMTVweDt9CiAgLnNpZGVuYXYgYSB7Zm9udC1zaXplOiAxOHB4O30KfQo8L3N0eWxlPgoKPCEtLSBUSVRMRSBJTkZPICAtLT4KCjxkaXYgY2xhc3M9InNpZGVuYXYiPgogIDxhIGhyZWY9IiNhYm91dCI+U2VhdHRsZSBQZXRzPC9hPgogIDxhIGhyZWY9IiN0b3AiPiA8Zm9udCBmYWNlPSJSb2JvdG8iIHNpemU9IjIiIGNvbG9yPSAiIzFmNzhiNCI+IHRvcCBvZiBwYWdlIDwvZm9udD48L2E+CjwvZGl2PgoKPCEtLSBDT05URU5UIFNUQVJUUyBIRVJFICAtLT4KCjxkaXYgY2xhc3M9Im1haW4iPgo8ZGl2IGNsYXNzPSJib2R5Ij4KCiMjQXV0aG9yOiBfXzxmb250IGNvbG9yPSIjZTMxYTFjIj5KZXNzaWNhIE1hcng8L2ZvbnQ+X18KCiMjRGF0ZTogX188Zm9udCBjb2xvcj0iI2UzMWExYyI7IGZvbnQgc2l6ZT0iMyI+YHIgZm9ybWF0KFN5cy50aW1lKCksICIlZCAlQiAlWSIpYDwvZm9udD5fXwoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQoKYGBgCgpgYGB7ciBwYWNrYWdlLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyBsb2FkIHBhY2thZ2VzLCBpbnN0YWxsIGlmIG5lZWRlZApwYWNrYWdlcyA9IGMoCiAgICAgICJkcGx5ciIKICAgICwgImdncGxvdDIiCiAgICAsICJmb3JtYXR0YWJsZSIKICAgICwgInBsb3RseSIKICAgICwgIlJDb2xvckJyZXdlciIKICAgICwgInNjYWxlcyIKICAgICwgInN0cmluZ3IiCiAgICAsICJ0aWR5ciIKICAgICwgIkVsbWVSIgogICAgLCAiUkpEQkMiCiAgICAsICJrYWJsZUV4dHJhIgogICAgLCAid2VzYW5kZXJzb24iCiAgICAsICJyZXNoYXBlMiIKICAgICwgInJ0d2VldCIKICAgICwgInRpZHl0ZXh0IgogICAgLCAibHVicmlkYXRlIgogICAgLCAid29yZGNsb3VkIgogICAgLCAiZ2dwdWJyIgogICAgLCAiZ2d0aGVtZXMiCiAgICAsICJrbml0ckJvb3RzdHJhcCIKICAgICwgIkRUIgogICAgLCAiTWF0Y2hJdCIKICAgICwgImJleW9uY2UiCiAgICAsICJVcFNldFIiCiAgICAsICJnZ2FuaW1hdGUiCiAgICAsICJ3b3JkY2xvdWQyIgogICAgLCAid2lkeXIiCiAgICAsICJnZ3JhcGgiCiAgICAsICJpZ3JhcGgiCiAgICAsICJhb2QiCiAgICAsICJjb3JycGxvdCIKICAgICwgIlJPQ1IiCiAgICAsICJJbmZvcm1hdGlvblZhbHVlIgogICAgLCAiY2FyIgogICAgLCAiZ2xtbmV0IgogICAgLCAiY2FyZXQiCiAgICAsICJrZXJubGFiIgogICAgLCAicGRwIgogICAgLCAicnBhcnQucGxvdCIKICAgICwgInJwYXJ0IgogICAgLCAiZTEwNzEiCiAgICApCgpwYWNrYWdlLmNoZWNrIDwtIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgewogIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUpCiAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKICB9Cn0pCgoKb3B0aW9ucyhzY2lwZW49IDk5OSkKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gOSwgYmFzZV9mYW1pbHkgPSAiUm9ib3RvIikpCmBgYAoKYGBge3IgZnVuY3Rpb25zfQoKI2Z1bmN0aW9ucyEKCiNyb3VuZCAKcm91bmQudG8gPC0gZnVuY3Rpb24oeCwgYikgewogIHJvdW5kKHgvYikqYgp9Cgojb2RkcyB0byBwcm9iYWJpbGl0eQpvZGRzLnRvLnByb2IgPC0gZnVuY3Rpb24ob2RkcykgewogIG9kZHMvKDEgKyBvZGRzKSAKfQoKI2xvZyBvZGRzIHRvIHByb2JhYmlsaXR5IApsb2dpdDJwcm9iIDwtIGZ1bmN0aW9uKGxvZ2l0KXsKICBvZGRzIDwtIGV4cChsb2dpdCkKICBwcm9iIDwtIG9kZHMgLyAoMSArIG9kZHMpCiAgcmV0dXJuKHByb2IpCn0KCiNjb252ZXJ0IHRvIGEgcmFuZ2UKcmFuZ2UwMSA8LSBmdW5jdGlvbih4KXsKICAoeC1taW4oeCkpLyhtYXgoeCktbWluKHgpKQp9CgojZnVuY3Rpb24gdG8gZ2V0IHZlY3RvciBvZiBjb2xvciB2YWx1ZXMgZnJvbSBSQ29sb3JCcmV3ZXIKZ2V0X2hleF92YWx1ZXMgPC0gZnVuY3Rpb24ocGFsKSB7CglicmV3ZXIucGFsKGJyZXdlci5wYWwuaW5mb1twYWwsICJtYXhjb2xvcnMiXSwgcGFsKQp9CnBhaXJlZF9jb2xzIDwtIGdldF9oZXhfdmFsdWVzKHBhbCA9ICJQYWlyZWQiKQoKCmBgYAoKIyNUb3AgRG9nIEJyZWVkcyAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04fQoKYSA9IHNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKICBmaWx0ZXIoc3BlY2llcyA9PSAiRG9nIikgJT4lIAogIHNlbGVjdChwcmltYXJ5X2JyZWVkLCBsaWNlbnNlX2lzc3VlX2RhdGUpICU+JSAKICBtdXRhdGUobGljZW5zZV9pc3N1ZV9kYXRlID0gYXMuRGF0ZShsaWNlbnNlX2lzc3VlX2RhdGUpLAogICAgICAgICB5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKGxpY2Vuc2VfaXNzdWVfZGF0ZSkpICU+JSAKICBncm91cF9ieShwcmltYXJ5X2JyZWVkLCB5ZWFyKSAlPiUgCiAgY291bnQoKSAlPiUgCiAgYXJyYW5nZSh5ZWFyLCBkZXNjKG4pKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieSh5ZWFyKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSByb3dfbnVtYmVyKCkpICU+JSAKICBmaWx0ZXIocmFuayA8PSA1LCB5ZWFyID49IDIwMTApICU+JQogIG11dGF0ZShyZXZfcmFuayA9IHJhbmsoLXJhbmspKSAlPiUgCiAgdW5ncm91cCgpIAoKY29sb3VyQ291bnQgPSBsZW5ndGgodW5pcXVlKGEkcHJpbWFyeV9icmVlZCkpCmdldFBhbGV0dGUgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoMTIsICJQYWlyZWQiKSkKCmdncGxvdChhLCBhZXMoeCA9IHllYXIsIHkgPSByZW9yZGVyKHJldl9yYW5rLCByZXZfcmFuayksIGZpbGwgPSBwcmltYXJ5X2JyZWVkKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gIndoaXRlIikgKyAKICBnZW9tX3RleHQoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIiwgYWVzKGxhYmVsID0gcmFuayksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIHZqdXN0ID0gMSwgaGp1c3QgPSAzKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDEwLCAyMDE2LCAxKSkgKyAKICBjb29yZF9mbGlwKCkgKwogIHlsYWIoInJhbmsiKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdldFBhbGV0dGUoY29sb3VyQ291bnQpLCBuYW1lID0gIkJyZWVkIikgKyAgCiAgZ2d0aXRsZShsYWJlbCA9ICJUb3AgRml2ZSBTZWF0dGxlIERvZyBCcmVlZHMgYnkgWWVhciIpCgoKYGBgCgojI0JyZWVkIEFjY2VsZXJhdGlvbiAKCmBgYHtyfQoKYSA9IHNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKICBmaWx0ZXIoc3BlY2llcyA9PSAiRG9nIikgJT4lIAogIHNlbGVjdChwcmltYXJ5X2JyZWVkLCBsaWNlbnNlX2lzc3VlX2RhdGUpICU+JSAKICBtdXRhdGUobGljZW5zZV9pc3N1ZV9kYXRlID0gYXMuRGF0ZShsaWNlbnNlX2lzc3VlX2RhdGUpLAogICAgICAgICB5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKGxpY2Vuc2VfaXNzdWVfZGF0ZSkpICU+JSAKICBmaWx0ZXIoeWVhciA+PSAyMDE1KSAlPiUgCiAgZ3JvdXBfYnkocHJpbWFyeV9icmVlZCwgeWVhcikgJT4lIAogIGNvdW50KCkgJT4lCiAgc3ByZWFkKHllYXIsIG4pICU+JSAKICBkcm9wX25hKCkgJT4lIAogIG11dGF0ZShwY3RfaW5jcmVhc2UgPSBgMjAxNmAvYDIwMTVgLTEpICU+JSAKICBhcnJhbmdlKGRlc2MocGN0X2luY3JlYXNlKSkgJT4lIAogIGhlYWQoMjApICU+JSAKICB1bmdyb3VwKCkKCmIgPSBzZWF0dGxlX3BldF9saWNlbnNlcyAlPiUgCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIpICU+JSAKICBzZWxlY3Qoc2Vjb25kYXJ5X2JyZWVkLCBsaWNlbnNlX2lzc3VlX2RhdGUpICU+JSAKICBtdXRhdGUobGljZW5zZV9pc3N1ZV9kYXRlID0gYXMuRGF0ZShsaWNlbnNlX2lzc3VlX2RhdGUpLAogICAgICAgICB5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKGxpY2Vuc2VfaXNzdWVfZGF0ZSkpICU+JSAKICBmaWx0ZXIoeWVhciA+PSAyMDE1KSAlPiUgCiAgZ3JvdXBfYnkoc2Vjb25kYXJ5X2JyZWVkLCB5ZWFyKSAlPiUgCiAgY291bnQoKSAlPiUKICBzcHJlYWQoeWVhciwgbikgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgbXV0YXRlKHBjdF9pbmNyZWFzZSA9IGAyMDE2YC9gMjAxNWAtMSkgJT4lIAogIGFycmFuZ2UoZGVzYyhwY3RfaW5jcmVhc2UpKSAlPiUgCiAgaGVhZCgyMCkgJT4lIAogIHVuZ3JvdXAoKQoKYnJlZWRzID0gYSAlPiUgCiAgc2VsZWN0KHByaW1hcnlfYnJlZWQsIHBjdF9pbmNyZWFzZSkgJT4lIAogIHJlbmFtZSgiYnJlZWQiID0gcHJpbWFyeV9icmVlZCkgJT4lIAogIG11dGF0ZShicmVlZF9sZXZlbCA9ICJQcmltYXJ5IEJyZWVkIikgJT4lIAogIHJiaW5kKAogICAgYiAlPiUgCiAgc2VsZWN0KHNlY29uZGFyeV9icmVlZCwgcGN0X2luY3JlYXNlKSAlPiUgCiAgcmVuYW1lKCJicmVlZCIgPSBzZWNvbmRhcnlfYnJlZWQpICU+JSAKICBtdXRhdGUoYnJlZWRfbGV2ZWwgPSAiU2Vjb25kYXJ5IEJyZWVkIikKICApICU+JSAKICBncm91cF9ieShicmVlZF9sZXZlbCkgJT4lIAogIGFycmFuZ2UoYnJlZWRfbGV2ZWwsIGRlc2MocGN0X2luY3JlYXNlKSkgJT4lIAogIG11dGF0ZShyYW5rID0gcm93X251bWJlcigpKSAlPiUgCiAgdW5ncm91cCgpCiAgCmNvbG91ckNvdW50ID0gbGVuZ3RoKHVuaXF1ZShicmVlZHMkYnJlZWQpKQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDEyLCAiUGFpcmVkIikpCgpicmVlZHMgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoYnJlZWQsIC1yYW5rKSwgeSA9IHBjdF9pbmNyZWFzZSwgZmlsbCA9IGJyZWVkKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdldFBhbGV0dGUoY29sb3VyQ291bnQpLCBuYW1lID0gIkJyZWVkIikgKyAgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsKICB5bGFiKCJQZXJjZW50IEluY3JlYXNlIikgKyAKICB4bGFiKCJCcmVlZCIpICsgCiAgZ2d0aXRsZShsYWJlbCA9ICJZZWFyIE92ZXIgWWVhciAoWU9ZKSBJbmNyZWFzZSBpbiBCcmVlZHMiKSArIAogICAgY29vcmRfZmxpcCgpICsgCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgCiAgZmFjZXRfd3JhcCh+YnJlZWRfbGV2ZWwsIHNjYWxlcyA9ICJmcmVlX3kiKQoKCmBgYAoKIyNEb2cgTmFtZXMKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04fQoKYSA9IHNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKICBmaWx0ZXIoc3BlY2llcyA9PSAiRG9nIiwKICAgICAgICAgIWlzLm5hKGFuaW1hbF9zX25hbWUpKSAlPiUgCiAgc2VsZWN0KGFuaW1hbF9zX25hbWUsIGxpY2Vuc2VfaXNzdWVfZGF0ZSkgJT4lIAogIG11dGF0ZShhbmltYWxfc19uYW1lID0gaWZfZWxzZShpcy5uYShhbmltYWxfc19uYW1lKSwgIk5vIE5hbWUiLCBhbmltYWxfc19uYW1lKSAsCiAgICAgICAgIGxpY2Vuc2VfaXNzdWVfZGF0ZSA9IGFzLkRhdGUobGljZW5zZV9pc3N1ZV9kYXRlKSwKICAgICAgICAgeWVhciA9IGx1YnJpZGF0ZTo6eWVhcihsaWNlbnNlX2lzc3VlX2RhdGUpKSAlPiUgCiAgZ3JvdXBfYnkoYW5pbWFsX3NfbmFtZSwgeWVhcikgJT4lIAogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UoeWVhciwgZGVzYyhuKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ3JvdXBfYnkoeWVhcikgJT4lIAogIG11dGF0ZShyYW5rID0gcm93X251bWJlcigpKSAlPiUgCiAgZmlsdGVyKHJhbmsgPD0gNSwgeWVhciA+PSAyMDEwKSAlPiUKICBtdXRhdGUocmV2X3JhbmsgPSByYW5rKC1yYW5rKSkgJT4lIAogIHVuZ3JvdXAoKSAKCmNvbG91ckNvdW50ID0gbGVuZ3RoKHVuaXF1ZShhJGFuaW1hbF9zX25hbWUpKQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDEyLCAiUGFpcmVkIikpCgpnZ3Bsb3QoYSwgYWVzKHggPSB5ZWFyLCB5ID0gcmVvcmRlcihyZXZfcmFuaywgcmV2X3JhbmspLCBmaWxsID0gYW5pbWFsX3NfbmFtZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJ3aGl0ZSIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZ2V0UGFsZXR0ZShjb2xvdXJDb3VudCksIG5hbWUgPSAiTmFtZSIpICsgIAogIGdlb21fdGV4dChzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siLCBhZXMobGFiZWwgPSByYW5rKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgdmp1c3QgPSAxLCBoanVzdCA9IDMpICsgCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMTAsIDIwMTYsIDEpKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgeWxhYigicmFuayIpICsgCiAgCiAgZ2d0aXRsZShsYWJlbCA9ICJUb3AgRml2ZSBTZWF0dGxlIERvZyBOYW1lcyBieSBZZWFyIikKCgpgYGAKCiMjQnJlZWQgQ29tYm9zIHsudGFic2V0fQoKIyMjQnJlZWQgSGVhdG1hcApXaGljaCBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgYnJlZWsgY29tYmluYXRpb25zIGFyZSBtb3N0IHBvcHVsYXI/IAoKYGBge3J9Cgp0b3BfYnJlZWRzID0gcmJpbmQoCihzZWF0dGxlX3BldF9saWNlbnNlcyAlPiUgCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIpICU+JSAKICBzZWxlY3QocHJpbWFyeV9icmVlZCkgJT4lIAogIGdyb3VwX2J5X2FsbCgpICU+JSAKICBjb3VudCgpICU+JSAKICBhcnJhbmdlKGRlc2MobikpICU+JSAKICBoZWFkKDIwKSAlPiUgCiAgcmVuYW1lKCJicmVlZCIgPSBwcmltYXJ5X2JyZWVkKSksCihzZWF0dGxlX3BldF9saWNlbnNlcyAlPiUgCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIpICU+JSAKICBzZWxlY3Qoc2Vjb25kYXJ5X2JyZWVkKSAlPiUgCiAgZ3JvdXBfYnlfYWxsKCkgJT4lIAogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAogIGhlYWQoMjApICU+JSAKICByZW5hbWUoImJyZWVkIiA9IHNlY29uZGFyeV9icmVlZCkKKSkgJT4lIAogIGdyb3VwX2J5KGJyZWVkKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpICU+JSAKICBhcnJhbmdlKGRlc2MobikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShicmVlZCA9IGlmX2Vsc2UoaXMubmEoYnJlZWQpLCAiVW5rbm93biIsIGJyZWVkKSkKCnBsb3QgPSBzZWF0dGxlX3BldF9saWNlbnNlcyAlPiUgCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIsIAogICAgICAgICBwcmltYXJ5X2JyZWVkICVpbiUgdG9wX2JyZWVkcyRicmVlZAogICAgICAgICAsc2Vjb25kYXJ5X2JyZWVkICVpbiUgdG9wX2JyZWVkcyRicmVlZAogICAgICAgICApICU+JSAKICBzZWxlY3QocHJpbWFyeV9icmVlZCwgc2Vjb25kYXJ5X2JyZWVkKSAlPiUgCiAgbXV0YXRlKHNlY29uZGFyeV9icmVlZCA9IGlmX2Vsc2UoaXMubmEoc2Vjb25kYXJ5X2JyZWVkKSwgcHJpbWFyeV9icmVlZCwgc2Vjb25kYXJ5X2JyZWVkKSkgJT4lIAogIGdyb3VwX2J5X2FsbCgpICU+JSAKICBjb3VudCgpICU+JSAKICBhcnJhbmdlKGRlc2MobikpICU+JSAKICAjaGVhZCg1MCkgJT4lIAogIG11dGF0ZShsb2cgPSBsb2cobiArIDEpKSAlPiUgCiAgZ2dwbG90KAogICAgYWVzKHggPSBwcmltYXJ5X2JyZWVkLAogICAgICAgIHkgPSBzZWNvbmRhcnlfYnJlZWQsIAogICAgICAgIGZpbGwgPSBsb2csCiAgICAgICAgdGV4dCA9IHBhc3RlKAogICAgICAgICAgIlByaW1hcnkgQnJlZWQ6IiwgcHJpbWFyeV9icmVlZCwKICAgICAgICAgICI8YnI+U2Vjb25kYXJ5IEJyZWVkOiIsIHNlY29uZGFyeV9icmVlZCwKICAgICAgICAgICI8YnI+RG9nczoiLCBjb21tYShuKQogICAgICAgICkKICAgICAgKQogICAgKSArIAogIGdlb21fdGlsZSgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zMCwgaGp1c3QgPSAwKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gYmx1ZXM5LAogICAgbmEudmFsdWUgPSAid2hpdGUiLAogICAgYnJlYWtzPWMoMCw3KSwKICAgICMgIyAjICNicmVha3MgPSBjKDQwMCwgNzAwMDAwKSwKICAgIGxhYmVscz1jKCIwIiwiMUsiKSwKICAgIGxpbWl0cz1jKDAsNyksCiAgICAjICMgIyAjbGltaXRzID0gYyg0MDAsIDcwMDAwMCksCiAgICBuYW1lID0gIkRvZ3MiKSArCiAgeWxhYigiU2Vjb25kYXJ5IEJyZWVkIikgKwogIHhsYWIoIlByaW1hcnkgQnJlZWQiKSAKCmdncGxvdGx5KHBsb3QsIHRvb2x0aXAgPSAidGV4dCIpICU+JSAKICBsYXlvdXQoYXV0b3NpemUgPSBGLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNjAwKQoKYGBgCjxicj4KPGJyPgo8YnI+Cjxicj4gCgojIyNVcHNldCBQbG90IChsaWtlIGEgVmVubiBEaWFncmFtLCBidXQgYmV0dGVyKQo8YnI+CjxpbWcgc3JjPSJzZWF0dGxlX2RvZ3MucG5nIiBhbHQ9IiIgd2lkdGg9IjgwMCIvPgo8YnI+CgotLS0KCgpgYGB7cn0KCiNUaGlzIGlzIHRoZSB0cnVlIGNvZGUgZm9yIHRoaXMgcGxvdC4gVW5mb3J0dW5hdGVseSwgdGhpcyBwYWNrYWdlIGhhcyBhIGJ1ZyAtLSBvbmUgdGhhdCBwcmludHMgYSBnaWFudCBibGFuayBzcGFjZSBiZWZvcmUgdGhlIHBsb3QsIHdoaWNoIG1ha2VzIGl0IGxlc3MgdGhhbiBvcHRpbWFsIGZvciBwdWJsaXNoaW5nLiBNeSBoYWNrIGFyb3VuZCB0aGlzIGlzIHRvIHJlcHJvZHVjZSB0aGUgcGxvdCB1c2luZyB0aGlzIGNvZGUgYW5kIHNhdmUgdGhlIGltYWdlIGluIG15IFIgUHJvamVjdCBmaWxlLiBGcm9tIHRoZXJlIEkgY2FuIGp1c3QgcHVsbCBpdCBpbiB3aXRoIGh0bWwuIEEgaGFjaywgeWVzLCBidXQgb25lIHRoYXQgd29ya3MgdW50aWwgdGhlIGJ1ZyBpcyBmaXhlZCAoYWNjb3JkaW5nIHRvIHRoZWlyIEdpdEh1YiBwYWdlLCBpdCdzIGEgV0lQISkuIAoKIyB1cHNldF9kb2cgPSByYmluZCgKIyAoc2VhdHRsZV9wZXRfbGljZW5zZXMgJT4lIAojICAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIpICU+JSAKIyAgICBtdXRhdGUocHJpbWFyeV9icmVlZCA9IGlmX2Vsc2UoaXMubmEocHJpbWFyeV9icmVlZCksICJVbmtub3duIiwgcHJpbWFyeV9icmVlZCkpICU+JSAKIyAgIHNlbGVjdChwcmltYXJ5X2JyZWVkLCBsaWNlbnNlX251bWJlcikgJT4lIAojICAgcmVuYW1lKCJicmVlZCIgPSBwcmltYXJ5X2JyZWVkKSksCiMgKHNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKIyAgIGZpbHRlcihzcGVjaWVzID09ICJEb2ciKSAlPiUgCiMgICAgbXV0YXRlKHNlY29uZGFyeV9icmVlZCA9IGlmX2Vsc2UoaXMubmEoc2Vjb25kYXJ5X2JyZWVkKSwgIlVua25vd24iLCBzZWNvbmRhcnlfYnJlZWQpKSAlPiUgIAojICAgc2VsZWN0KHNlY29uZGFyeV9icmVlZCwgbGljZW5zZV9udW1iZXIpICU+JSAKIyAgIHJlbmFtZSgiYnJlZWQiID0gc2Vjb25kYXJ5X2JyZWVkKQojICkpICU+JSAKIyAgIGdyb3VwX2J5KGxpY2Vuc2VfbnVtYmVyLCBicmVlZCkgJT4lCiMgICBjb3VudCgpICU+JSAKIyAgIG11dGF0ZSh2YWx1ZSA9IDEpICU+JQojICAgc2VsZWN0KC1saWNlbnNlX251bWJlciwgLW4pICU+JSAKIyAgIHNwcmVhZChicmVlZCwgdmFsdWUsIGZpbGwgPSAwKSAlPiUKIyAgIGFzLmRhdGEuZnJhbWUoKQojIAojIHVwc2V0KHVwc2V0X2RvZywgCiMgICAgICAgb3JkZXIuYnkgPSAiZnJlcSIsCiMgICAgICAgbnNldHMgPSAxNSwgCiMgICAgICAgbWFpbmJhci55LmxhYmVsID0gIkRvZyBCcmVlZCBJbnRlcnNlY3Rpb25zIiwgCiMgICAgICAgc2V0cy54LmxhYmVsID0gIlRvdGFsIE51bWJlciBvZiBCcmVlZCBpbiBTYW1wbGUiLAojICAgICAgIG1hdHJpeC5jb2xvciA9ICIjMzI4OGJkIiwKIyAgICAgICBtYWluLmJhci5jb2xvciA9ICIjZjQ2ZDQzIiwKIyAgICAgICBzZXRzLmJhci5jb2xvciA9ICIjMzI4OGJkIiwgCiMgICAgICAgcG9pbnQuc2l6ZSA9IDIuNSwgbGluZS5zaXplID0gMSwgCiMgICAgICAgbmludGVyc2VjdHMgPSAxNSwKIyAgICAgICBzaGFkZS5jb2xvciA9ICIjOWUwMTQyIiwKIyAgICAgICB0ZXh0LnNjYWxlID0gYygxLjUsIDEuNSwgMS41LCAxLjUsIDEuNSwgMS41KSwKIyAgICAgICBncm91cC5ieSA9ICJkZWdyZWUiKQoKCgpgYGAKCgojIyNCcmVlZCBOZXR3b3JrCgpgYGB7ciBlY2hvID0gRkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD05fQoKYnJlZWRfcGFpcnMgPSBzZWF0dGxlX3BldF9saWNlbnNlcyAlPiUgCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkRvZyIpICU+JSAKICBzZWxlY3QocHJpbWFyeV9icmVlZCwgc2Vjb25kYXJ5X2JyZWVkKSAlPiUgCiAgcGFpcndpc2VfY291bnQocHJpbWFyeV9icmVlZCwgc2Vjb25kYXJ5X2JyZWVkLCBzb3J0ID0gVFJVRSkKCiMgbWFrZSBhbiBpbmRleCBlZy4gZXZlcnkgMm5kCmluZCA8LSBzZXEoMSwgbnJvdyhicmVlZF9wYWlycyksIGJ5PTIpCgojdGhpcyB3b3VsZCBleGNsdWRlIHRoZSBpbmQgcm93CmJyZWVkX3BhaXJzIDwtIGJyZWVkX3BhaXJzWy1pbmQsIF0gJT4lIAogIHJlbmFtZSgiZnJvbSIgPSBpdGVtMSwKICAgICAgICAgInRvIiA9IGl0ZW0yKQoKZWRnZXMgPC0gYnJlZWRfcGFpcnMgJT4lIAogIHJlbmFtZSgid2VpZ2h0IiA9IG4pICU+JSAKICBoZWFkKDEwMCkKbm9kZXMgPC0gZWRnZXMgJT4lIGdhdGhlcihpdGVtLCBpZCwgZnJvbSwgdG8pICU+JQogIGdyb3VwX2J5KGlkKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSh3ZWlnaHQgPSBzdW0od2VpZ2h0KSkgJT4lIAogIGFycmFuZ2UoZGVzYyh3ZWlnaHQpKSAlPiUgCiAgI211dGF0ZShpdGVtX3R5cGUgPSBpZl9lbHNlKGlkICVpbiUgYnJhbmRfdG90JGJyYW5kX25hbWUsICJEU05SIiwgIk5PTi1EU05SIikpICU+JSAKICB1bmdyb3VwKCkKCiMgYWRkaW5nIGRpZmZlcmVudCBmZWF0dXJlcyBpbnRvIHRoZSBub2Rlcwpub2RlcyRmb250LnNpemUgPSByZXNjYWxlKG5vZGVzJHdlaWdodCwgdG8gPSBjKDcwLCAyMDApKS9zYXBwbHkobm9kZXMkaWQsIGZ1bmN0aW9uKHgpIG5jaGFyKGFzLmNoYXJhY3Rlcih4KSkpCm5vZGVzJHNoYXBlID0gJ2NpcmNsZScKIyBhZGRpbmcgZGlmZmVyZW50IGZlYXR1cmVzIGludG8gdGhlIGVkZ2VzCmVkZ2VzJHdpZHRoID0gcmVzY2FsZShlZGdlcyR3ZWlnaHQsIHRvID0gYyg0LCAyNSkpCiNlZGdlcyRsZW5ndGggPSByZXNjYWxlKGVkZ2VzJHdpZHRoLCB0byA9IGMoMzAwLCA0MDApKQojIHVzZSB0aGUgZnJvbSBub2RlcyBjb2xvciBhcyB0aGUgY29sb3Igb2YgdGhlIGVkZ2VzCiNlZGdlcyRjb2xvciA9IG5vZGVzW1snY29sb3InXV1bZWRnZXNbWydmcm9tJ11dXQplZGdlcyRjb2xvciA9ICIjMWY3OGI0IgojIGNyZWF0ZSBhIGlncmFwaCBvYmplY3QgZm9yIGZ1dHVyZSBwbG90dGluZwpuZXQgPSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IGVkZ2VzLCB2ZXJ0aWNlcyA9IG5vZGVzKQoKbGlicmFyeSh2aXNOZXR3b3JrKQojIGludGVyYWN0aXZlIHBsb3Qgb2YgdGhlIGZlYXR1cmVzCnZpc05ldHdvcmsobm9kZXMsIGVkZ2VzKSU+JQogIHZpc0VkZ2VzKHNtb290aCA9IFRSVUUsIGRhc2hlcyA9IFRSVUUpICU+JQogIHZpc05vZGVzKHNoYWRvdyA9IFRSVUUsIGNvbG9yPWxpc3QoYmFja2dyb3VuZD0icGluayIsIGhpZ2hsaWdodD0iI2E2Y2VlMyIsIGJvcmRlcj0iYmxhY2siKSkgJT4lCiAgdmlzSWdyYXBoTGF5b3V0KGxheW91dCA9ICJsYXlvdXRfbmljZWx5IikgJT4lCiAgdmlzT3B0aW9ucyhoaWdobGlnaHROZWFyZXN0ID0gbGlzdChlbmFibGVkPVRSVUUsIGRlZ3JlZSA9IGxpc3QoZnJvbSA9IDEsIHRvID0gMSksIGxhYmVsT25seT1UUlVFKSkgJT4lIAogIHZpc0xheW91dChyYW5kb21TZWVkID0gMTIzNCkgCgpgYGAKCiMjQnJlZWQgQ2hhcmFjdGVyaXN0aWNzIHsudGFic2V0fQpXaGF0IGFyZSB0aGUgd29yZHMgdXNlZCB0byBkZXNjcmliZSBkaWZmZXJlbnQgZG9nIGJyZWVkcz8gQWxsIGJyZWVkIGRlc2NyaXB0aW9ucyB3ZXJlIG9idGFpbmVkIHRocm91Z2ggdGhlIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmthZ2dsZS5jb20vcnR1cmxleS9wZXQtYnJlZWQtY2hhcmFjdGVyaXN0aWNzIiB0YXJnZXQ9Il9ibGFuayI+UGV0IEJyZWVkcyBDaGFyYWN0ZXJpc3RpY3M8L2E+IHB1YmxpYyBkYXRhc2V0LgoKYGBge3J9CgphID0gZG9nX3dvcmRzICU+JSAKICBncm91cF9ieSh3b3JkKSAlPiUgCiAgY291bnQoKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBhcnJhbmdlKGRlc2MobikpCgp3b3JkY2xvdWQoYSR3b3JkLCBhJG4sICwgMiwgLEZBTFNFLCAsIC4xNSwgcmV2KGdldF9oZXhfdmFsdWVzKCJQYWlyZWQiKSkpCiN3b3JkY2xvdWQyKGEsIHNpemUgPSAuNSwgZmlnUGF0aCA9ICJkb2dfb3V0bGluZS5wbmciKQojbGV0dGVyQ2xvdWQoYSwgd29yZCA9ICJEIikKCgpgYGAKCldlIHdpbGwgc2NvcmUgdGhlIHRvcCAyMCBicmVlZHMgdXNpbmcgdGhlIEFGSU5OIGxleGljb24sIHdoaWNoIHNjb3JlcyB3b3JkcyBieSBzZW50aW1lbnQuIAo8YnI+Cjxicj4KCkJlZm9yZSBkb2luZyBzbywgbGV0J3MgaW5zcGVjdCB0aGUgZGF0YSBhbmQgbWFrZSBzdXJlIHRoYXQgd2UgYWdyZWUgd2l0aCB0aGUgd2F5IHRoZSBMZXhpY29uIGlzIGNsYXNzaWZ5aW5nIHdvcmRzIGdpdmVuIG91ciBzcGVjaWZpYyBjb250ZXh0LiAKCmBgYHtyfQoKQUZJTk4gPC0gZ2V0X3NlbnRpbWVudHMoImFmaW5uIikKCnBhbCA8LSByZXYoYmV5b25jZV9wYWxldHRlKDIyLCAxMDAsIHR5cGUgPSAiY29udGludW91cyIpKQoKcGxvdF9jID0gYmFyc2VudGltZW50ICU+JQogICAgZHBseXI6OmNvdW50KHNlbnRpbWVudCwgd29yZCwgbj1uKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkgCgpkb2dfYnJlZWRfY2hhcmFjdGVyaXN0aWNzICU+JSAKICBzZWxlY3QoQnJlZWROYW1lLCBHcm91cDEsIEdyb3VwMiwgVGVtcGVybWVudCkgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgVGVtcGVybWVudCkgJT4lIAogIGlubmVyX2pvaW4oQUZJTk4pICU+JSAKICBzZWxlY3Qod29yZCwgc2NvcmUpICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgYXJyYW5nZShkZXNjKHNjb3JlKSkgJT4lIAogIG11dGF0ZShTZW50aW1lbnQgPSBpZl9lbHNlKHNjb3JlID4gMCwgIlBvc2l0aXZlIiwgIk5lZ2F0aXZlIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKHdvcmQsIHNjb3JlKSwgeSA9IHNjb3JlLCBmaWxsID0gU2VudGltZW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsgCiAgY29vcmRfZmxpcCgpICsgCiAgeGxhYigiV29yZCIpICsgCiAgeWxhYigiU2NvcmUiKQoKYGBgCgpBIGRvZyBiZWluZyBfYWxlcnRfIGRvZXMgbm90IHNlZW0gbGlrZSBpdCB3b3VsZCBiZSBhIGJhZCB0aGluZyAtIGxldCdzIGNoYW5nZSB0aGF0IGZyb20gYSAtMSB0byBhICsxLiAKClNvbWUgZG9nIGJyZWVkcyBhcmUgZGVzY3JpYmVkIGJ5IG1vcmUgd29yZHMgdGhhbiBvdGhlcnMuIEEgaGlzdG9ncmFtIGhlbHBzIHVzIHZpc3VhbGl6ZSBhbmQgbm9ybWFsaXplIHRoZSBkYXRhLiAKCmBgYHtyfQoKQUZJTk4gPSBBRklOTiAlPiUgCiAgbXV0YXRlKHNjb3JlID0gaWZlbHNlKHdvcmQgPT0gImFsZXJ0IiwgMSwgc2NvcmUpKQoKZG9nX3dvcmRzID0gZG9nX2JyZWVkX2NoYXJhY3RlcmlzdGljcyAlPiUgCiAgc2VsZWN0KEJyZWVkTmFtZSwgR3JvdXAxLCBHcm91cDIsIFRlbXBlcm1lbnQpICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIFRlbXBlcm1lbnQpCgpkb2dfc2NvcmVzID0gZG9nX3dvcmRzICU+JSAKICBpbm5lcl9qb2luKEFGSU5OKSAlPiUgCiAgZ3JvdXBfYnkoQnJlZWROYW1lKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3Njb3JlID0gc3VtKHNjb3JlKSwKICAgICAgICAgICAgbWVkX3Njb3JlID0gbWVkaWFuKHNjb3JlKSwKICAgICAgICAgICAgdG90YWxfd29yZHMgPSBuX2Rpc3RpbmN0KHdvcmQpKSAlPiUgCiAgbXV0YXRlKG1lYW5fc2NvcmUgPSB0b3RhbF9zY29yZS90b3RhbF93b3JkcykKCmRvZ19zY29yZXMgJT4lIAogIGdhdGhlcihLUEksIHZhbHVlLCB0b3RhbF9zY29yZSwgdG90YWxfd29yZHMsIG1lYW5fc2NvcmUsIG1lZF9zY29yZSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHZhbHVlLCBmaWxsID0gS1BJKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSkgKyAKICBmYWNldF93cmFwKH5LUEksIHNjYWxlcyA9ICJmcmVlX3giKSArIAogIHhsYWIoIiIpICsgCiAgeWxhYigiRnJlcXVlbmN5IikgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpCgpgYGAKCk5vdyB3ZSdyZSByZWFkeSB0byBzY29yZSBvdXIgZG9ncyBieSBicmVlZC4gCgoKIyMjVG9wIDIwCgpgYGB7cn0KCmRvZ19zY29yZXMgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbF9zY29yZSkpICU+JSAKICBoZWFkKDIwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihCcmVlZE5hbWUsIHRvdGFsX3Njb3JlKSwgeSA9IHRvdGFsX3Njb3JlLCBmaWxsID0gdG90YWxfc2NvcmUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oCiAgICBjb2xvdXJzID0gcGFsLCBuYW1lID0gIlNjb3JlIikgKwogIGNvb3JkX2ZsaXAoKSArIAogIHhsYWIoIkJyZWVkIikgKyAKICB5bGFiKCJUb3RhbCBXb3JkIFNjb3JlIikKCmBgYAoKQXJlIGRvZ3Mgd2l0aCBtb3JlIHdvcmRzIHNjb3JlZCBoaWdoZXI/IFdlIGNhbiBub3JtYWxpemUgYnkgdGFraW5nIHRoZSBtZWFuIHdvcmQgc2NvcmUuIAoKYGBge3J9Cgpkb2dfc2NvcmVzICU+JSAKICBhcnJhbmdlKGRlc2MobWVhbl9zY29yZSksIEJyZWVkTmFtZSkgJT4lICAKICBoZWFkKDIwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihCcmVlZE5hbWUsIG1lYW5fc2NvcmUpLCB5ID0gbWVhbl9zY29yZSwgZmlsbCA9IHRvdGFsX3Njb3JlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKAogICAgY29sb3VycyA9IHBhbCwgbmFtZSA9ICJUb3RhbCBTY29yZSIpICsKICBjb29yZF9mbGlwKCkgKyAKICB4bGFiKCJCcmVlZCIpICsgCiAgeWxhYigiTWVhbiBXb3JkIFNjb3JlIikKCmBgYAoKCjwhLS0gIyMjQm90dG9tIDIwIC0tPgoKPCEtLSBgYGB7cn0gLS0+Cgo8IS0tIHBhbCA8LSAoYmV5b25jZV9wYWxldHRlKDQ4LCAxMDAsIHR5cGUgPSAiY29udGludW91cyIpKSAtLT4KCjwhLS0gZG9nX3Njb3JlcyAlPiUgIC0tPgo8IS0tICAgYXJyYW5nZShtZWFuX3Njb3JlKSAlPiUgIC0tPgo8IS0tICAgaGVhZCgyMCkgJT4lICAtLT4KPCEtLSAgIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoQnJlZWROYW1lLCBzY29yZSksIHkgPSBzY29yZSwgZmlsbCA9IHNjb3JlKSkgKyAtLT4KPCEtLSAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArICAtLT4KPCEtLSAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKCAtLT4KPCEtLSAgICAgY29sb3VycyA9IHBhbCwgbmFtZSA9ICJTY29yZSIpICsgLS0+CjwhLS0gICBjb29yZF9mbGlwKCkgKyAgLS0+CjwhLS0gICB4bGFiKCJCcmVlZCIpICsgIC0tPgo8IS0tICAgeWxhYigiU2NvcmUiKSAtLT4KCjwhLS0gYGBgIC0tPgoKIyMjVG9wIDIwIEJyZWVkIENvbWJvcwoKYGBge3J9CgpzZWF0dGxlX3BldF9saWNlbnNlcyRwcmltYXJ5X2JyZWVkIDwtIHN1YigiKFxcdyspLFxccyhcXHcrKSIsIlxcMiBcXDEiLCBzZWF0dGxlX3BldF9saWNlbnNlcyRwcmltYXJ5X2JyZWVkKQoKc2VhdHRsZV9wZXRfbGljZW5zZXMkc2Vjb25kYXJ5X2JyZWVkIDwtIHN1YigiKFxcdyspLFxccyhcXHcrKSIsIlxcMiBcXDEiLCBzZWF0dGxlX3BldF9saWNlbnNlcyRzZWNvbmRhcnlfYnJlZWQpCgpwYWwgPC0gcmV2KGJleW9uY2VfcGFsZXR0ZSgyMiwgMTAwLCB0eXBlID0gImNvbnRpbnVvdXMiKSkKCnNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKICBmaWx0ZXIoc3BlY2llcyA9PSAiRG9nIikgJT4lIAogIHNlbGVjdChwcmltYXJ5X2JyZWVkLCBzZWNvbmRhcnlfYnJlZWQpICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgbXV0YXRlKGlkID0gcm93X251bWJlcigpKSAlPiUgCiAgbGVmdF9qb2luKGRvZ19icmVlZF9jaGFyYWN0ZXJpc3RpY3MsIGJ5ID0gYygicHJpbWFyeV9icmVlZCIgPSAiQnJlZWROYW1lIikpICU+JSAKICBzZWxlY3QocHJpbWFyeV9icmVlZCwgc2Vjb25kYXJ5X2JyZWVkLCBpZCwgVGVtcGVybWVudCkgJT4lIAogIHJlbmFtZSgicHJpbWFyeV90ZW1wIiA9IFRlbXBlcm1lbnQpICU+JSAKICBsZWZ0X2pvaW4oZG9nX2JyZWVkX2NoYXJhY3RlcmlzdGljcywgYnkgPSBjKCJzZWNvbmRhcnlfYnJlZWQiID0gIkJyZWVkTmFtZSIpKSAlPiUgCiAgc2VsZWN0KHByaW1hcnlfYnJlZWQsIHNlY29uZGFyeV9icmVlZCwgaWQsIHByaW1hcnlfdGVtcCwgVGVtcGVybWVudCkgJT4lIAogIHJlbmFtZSgic2Vjb25kYXJ5X3RlbXAiID0gVGVtcGVybWVudCkgJT4lIAogIG11dGF0ZSh0ZW1wX2NvbWJvID0gcGFzdGUocHJpbWFyeV90ZW1wLCBzZWNvbmRhcnlfdGVtcCwgc2VwID0gIiwgIikpICU+JSAKICBzZWxlY3QoLXByaW1hcnlfdGVtcCwgLXNlY29uZGFyeV90ZW1wKSAlPiUgCnVubmVzdF90b2tlbnMod29yZCwgdGVtcF9jb21ibykgJT4lIAogIG11dGF0ZShicmVlZF9jb21ibyA9IHBhc3RlKHByaW1hcnlfYnJlZWQsIHNlY29uZGFyeV9icmVlZCwgc2VwID0gIiArICIpKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBzZWxlY3QoLXByaW1hcnlfYnJlZWQsIC1zZWNvbmRhcnlfYnJlZWQpICU+JSAKICBpbm5lcl9qb2luKEFGSU5OKSAlPiUgCiAgZ3JvdXBfYnkoaWQsIGJyZWVkX2NvbWJvKSAlPiUgCiAgc3VtbWFyaXNlKGF2Z19zY29yZSA9IG1lYW4oc2NvcmUpLAogICAgICAgICAgICBzY29yZSA9IHN1bShzY29yZSkpICU+JSAKICBhcnJhbmdlKGRlc2MoYXZnX3Njb3JlKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSBkZW5zZV9yYW5rKC1hdmdfc2NvcmUpKSAlPiUgCiAgaGVhZCgyMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoYnJlZWRfY29tYm8sIGF2Z19zY29yZSksIHkgPSBhdmdfc2NvcmUsIGZpbGwgPSBzY29yZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBnZW9tX3RleHQoc3RhdCA9ICJpZGVudGl0eSIsIHNpemUgPSAzLCBoanVzdCA9IC0xLCBhZXMobGFiZWwgPSByYW5rKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gcGFsLCBuYW1lID0gIlNjb3JlIikgKwogIGNvb3JkX2ZsaXAoKSArIAogIHhsYWIoIkJyZWVkIikgKyAKICB5bGFiKCJTY29yZSIpCiAgCgpgYGAKCiMjI0J5IEdyb3VwIAoKTGV0J3MgaGVhciBpdCBmb3IgdGhlIHRoZSBIb3VuZHMhIAoKYGBge3J9Cgpncm91cF9zY29yZXMgPSBkb2dfd29yZHMgJT4lIAogIGZpbHRlcighR3JvdXAxID09ICJTb3V0aGVybiIpICU+JSAKICBzZWxlY3QoR3JvdXAxLCB3b3JkKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGlubmVyX2pvaW4oQUZJTk4pICU+JSAKICBncm91cF9ieShHcm91cDEpICU+JSAKICBzdW1tYXJpc2UoYXZnX3Njb3JlID0gbWVhbihzY29yZSksCiAgICAgICAgICAgIHNjb3JlID0gc3VtKHNjb3JlKSkgJT4lIAogIGRyb3BfbmEoKQoKZ3JvdXBfc2NvcmVzICU+JSAKICBhcnJhbmdlKGRlc2MoYXZnX3Njb3JlKSkgJT4lIAogICNoZWFkKDIwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihHcm91cDEsIGF2Z19zY29yZSksIHkgPSBhdmdfc2NvcmUsIGZpbGwgPSBzY29yZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bigKICAgIGNvbG91cnMgPSBwYWwsIG5hbWUgPSAiVG90YWwgU2NvcmUiKSArCiAgY29vcmRfZmxpcCgpICsgCiAgeGxhYigiQnJlZWQgR3JvdXAiKSArIAogIHlsYWIoIk1lYW4gU2NvcmUiKQoKYGBgCgojIyNCcmVlZCBHcm91cCAxICsgR3JvdXAgMgoKYGBge3J9Cgpncm91cF9ib3RoID0gZG9nX3dvcmRzICU+JSAKICBmaWx0ZXIoIUdyb3VwMSA9PSAiU291dGhlcm4iKSAlPiUgCiAgaW5uZXJfam9pbihBRklOTikgJT4lIAogIG11dGF0ZShncm91cF9jb21ibyA9IHBhc3RlKEdyb3VwMSwgR3JvdXAyLCBzZXAgPSAiICsgIikpICU+JSAKICBncm91cF9ieShncm91cF9jb21ibykgJT4lIAogIHN1bW1hcmlzZSgKICAgIGF2Z19zY29yZSA9IG1lYW4oc2NvcmUpLCAKICAgIHNjb3JlID0gc3VtKHNjb3JlKQogICAgKSAlPiUgCiAgI3N1bW1hcmlzZShjb3VudCA9IG5fZGlzdGluY3Qod29yZCkpICU+JSAKICBkcm9wX25hKCkKCmdyb3VwX2JvdGggJT4lIAogIGFycmFuZ2UoZGVzYyhhdmdfc2NvcmUpKSAlPiUgCiAgI2hlYWQoMjApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGdyb3VwX2NvbWJvLCBhdmdfc2NvcmUpLCB5ID0gYXZnX3Njb3JlLCBmaWxsID0gc2NvcmUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oCiAgICBjb2xvdXJzID0gcGFsLCBuYW1lID0gIlRvdGFsIFNjb3JlIikgKwogIGNvb3JkX2ZsaXAoKSArIAogIHhsYWIoIkJyZWVkIEdyb3VwIDEgKyBCcmVlZCBHcm91cCAyIikgKyAKICB5bGFiKCJNZWFuIFNjb3JlIikKCmBgYAoKIyMjSW50ZWxsaWdlbmNlIFJhdGluZ3MKRG9lcyBpbnRlbGxpZ2VuY2UgY29ycmVzcG9uZCB3aXRoIHByaWNlPyBOby4gCgpgYGB7cn0KCmRvZ19icmVlZF9jaGFyYWN0ZXJpc3RpY3MgJT4lIAogIHNlbGVjdChCcmVlZE5hbWUsIEludGVsbGlnZW5jZSwgQXZnUHVwUHJpY2UpICU+JSAKICBhcnJhbmdlKGRlc2MoSW50ZWxsaWdlbmNlKSkgJT4lIAogIGhlYWQoMzApICU+JSAKICBtdXRhdGUoQnJlZWROYW1lID0gcmVvcmRlcihCcmVlZE5hbWUsIC1JbnRlbGxpZ2VuY2UpKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBwbG90X2x5KAogICAgeCA9IH5CcmVlZE5hbWUKICAgICwgeSA9IH5JbnRlbGxpZ2VuY2UKICAgICwgdHlwZSA9ICJiYXIiCiAgICAsIG5hbWUgPSB+cGFzdGUoIkludGVsbGlnZW5jZSIpCiAgICAsIGhlaWdodCA9IDUwMAogICAgLCB3aWR0aCA9IDEwMDAKICAgICMsIGxlZ2VuZGdyb3VwID0gfkludGVsbGlnZW5jZQogICAgLCB0ZXh0ID0gfnBhc3RlKAogICAgICAgICJCcmVlZDoiLCBCcmVlZE5hbWUKICAgICAgICAsICI8YnI+SW50ZWxsaWdlbmNlIFJhdGluZzoiLCBJbnRlbGxpZ2VuY2UKICAgICAgICAsICI8YnI+QXZlcmFnZSBQdXBweSBQcmljZToiLCBkb2xsYXIoQXZnUHVwUHJpY2UpCiAgICAgICAgKQogICAgLCBob3ZlcmluZm8gPSAndGV4dCcKICApICU+JSAKICBhZGRfdHJhY2UoCiAgICB5ID0gfkF2Z1B1cFByaWNlCiAgICAsIHR5cGUgPSAic2NhdHRlciIKICAgICwgbW9kZSA9ICJsaW5lcyttYXJrZXJzIgogICAgLCB5YXhpcyA9ICJ5MiIKICAgICwgbmFtZSA9IH5wYXN0ZSgiQXZnIFByaWNlIikKICApICU+JSAKICBsYXlvdXQoCiAgICB5YXhpczIgPSBsaXN0KAogICAgICBzaWRlID0gInJpZ2h0IgogICAgICAsIG92ZXJsYXlpbmcgPSAieSIKICAgICAgLCB0aXRsZSA9ICJBdmcgRG9nIFByaWNlICQiCiAgICApCiAgICAsIHhheGlzID0gbGlzdCgKICAgICAgdGlja2FuZ2xlID0gMzAKICAgICAgLCB0aXRsZSA9ICJCcmVlZCIKICAgICkKICApCiAgCgpgYGAKCgojI1BldHMgYnkgWmlwIFlPWQpgYGB7cn0KCnNlYXR0bGVfcGV0X2xpY2Vuc2VzICU+JSAKICAgIGRyb3BfbmEoKSAlPiUgCiAgc2VsZWN0KGxpY2Vuc2VfaXNzdWVfZGF0ZQogICAgICAgICAsIHNwZWNpZXMKICAgICAgICAgLCB6aXBfY29kZQogICAgICAgICAsIGxpY2Vuc2VfbnVtYmVyKSAlPiUgCiAgbXV0YXRlKGxpY2Vuc2VfaXNzdWVfZGF0ZSA9IGFzLkRhdGUobGljZW5zZV9pc3N1ZV9kYXRlKSwKICAgICAgICAgeWVhciA9IGx1YnJpZGF0ZTo6eWVhcihsaWNlbnNlX2lzc3VlX2RhdGUpLAogICAgICAgICB6aXBfY29kZSA9IChhcy5mYWN0b3IoemlwX2NvZGUpKQogICAgICAgICApICU+JQogIGdyb3VwX2J5KHllYXIsIHppcF9jb2RlLCBzcGVjaWVzKSAlPiUgCiAgc3VtbWFyaXNlKG5ld19wZXRzID0gbl9kaXN0aW5jdChsaWNlbnNlX251bWJlcikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHBsb3RfbHkoCiAgeCA9IH56aXBfY29kZQogICwgeSA9IH5uZXdfcGV0cwogICwgY29sb3IgPSB+c3BlY2llcwogICwgdHlwZSA9ICJiYXIiCiAgLCBsZWdlbmRfZ3JvdXAgPSB+c3BlY2llcwogICwgZnJhbWUgPSB+eWVhcgogICkgJT4lIAogIGxheW91dCgKICAgIGJhcm1vZGUgPSAic3RhY2siCiAgICAsIHhheGlzID0gbGlzdCh0aXRsZSA9ICJaaXAgQ29kZSIpCiAgICAsIHlheGlzID0gbGlzdCh0aXRsZSA9ICJOZXcgUGV0cyIpCiAgKQoKYGBgCgoK